# 函数的返回值可以是一个函数，并且每次返回的是新的函数，各个函数之间的调用互不影响
def lazy_sum(*args):
    def sum():
        ax = 0
        for n in args:
            ax = ax + n
        return ax
    return sum

f1 = lazy_sum(1, 3, 5, 7, 9)
f2 = lazy_sum(1, 3, 5, 7, 9)
print(f1 == f2)

# 这种在函数内定义的函数称为闭包，这种闭包结构可以引用外部函数的参数和局部变量，并且只在真正被调用的时候才会被执行
def count():
    fs = []
    for i in range(1, 4):
        def f():
             return i*i
        fs.append(f)
    return fs

f1, f2, f3 = count()
print(f1())
print(f2())
print(f3())
# 上述 count 函数定义了三个新的函数，并且进行了返回，但真正调用新函数的时候是在 print 里，此时循环变量 i 已经变成了 3，因此每个函数的输出结果都是 9

# 闭包函数可以直接引用外部函数的变量，直接读取外边函数的变量值的时候没有问题，但是当对外部变量赋值的时候就会提示报错，原因是在闭包函数内引用的外部函数的变量会被当作
# 当前闭包函数内的局部变量，因此如果没有在闭包函数内初始化就直接引用赋值的话会报错
def inc():
    x = 0
    def fn():
        # 仅读取x的值:
        return x + 1
    return fn

f = inc()
print(f()) # 1
print(f()) # 1

# 此时需要用nonlocal将x声明为非局部变量，即可引用外部变量的初始化
def inc():
    x = 0
    def fn():
        nonlocal x
        x = x + 1
        return x
    return fn

f = inc()
print(f()) # 1
print(f()) # 2
# 注意：闭包函数会延长变量的生命周期，普通函数在返回时变量已经被销毁了，而闭包函数内的变量只要闭包对象一直存在，就会一直存在，相当于“私有静态变量”
# 上述inc函数只被调用了一次，因此得到了一个闭包对象 f，当 f 一直存在且不断被调用时，闭包就记住了x 每次运行的结果

def createCounter():
    x = 0
    def counter():
        nonlocal x
        x = x + 1
        return x
    return counter

# 测试:
counterA = createCounter()
print(counterA(), counterA(), counterA(), counterA(), counterA()) # 1 2 3 4 5
counterB = createCounter()
if [counterB(), counterB(), counterB(), counterB()] == [1, 2, 3, 4]:
    print('测试通过!')
else:
    print('测试失败!')



